package com.sduept.nwld.dataserver.controller.document;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

import org.primefaces.PrimeFaces;
import org.primefaces.event.CellEditEvent;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.event.NodeExpandEvent;
import org.primefaces.event.NodeSelectEvent;
import org.primefaces.event.ReorderEvent;
import org.primefaces.event.SelectEvent;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.StreamedContent;
import org.primefaces.model.TreeNode;
import org.primefaces.model.UploadedFile;
import org.springframework.beans.factory.annotation.Autowired;

import com.sduept.bigdata.document.core.CommonDocumentProperties;
import com.sduept.bigdata.web.jsf.controller.AbstractController;
import com.sduept.generator.ObjectId;
import com.sduept.nwld.dataserver.manager.document.DocumentDirManager;
import com.sduept.nwld.dataserver.model.AppDocument;
import com.sduept.nwld.dataserver.model.AppDocumentDir;
import com.sduept.nwld.dataserver.util.LibTreeNode;
import com.sduept.utils.CharacterUtil;
import com.sduept.utils.ListUtils;

@Named
@ViewScoped
public class DocumentController extends AbstractController implements
		Serializable {
	/**
	 * 
	 */
	@Autowired
	private CommonDocumentProperties pros;
	private static final long serialVersionUID = -4306592078623341306L;
	@Autowired
	private DocumentDirManager docManager;
	private TreeNode root;
	private TreeNode currentSelectedNode;
	
	private List<AppDocumentDir> documentDirs;// 所有的文档目录
	private List<AppDocumentDir> tempDirs = new ArrayList<>();// 一个目录下的文档目录
	private List<AppDocument> list;//某个目录下的所有文档
	
	private AppDocumentDir createDir;//新建目录
	private AppDocumentDir selected = null;//选中的目录
	private AppDocument selectedDoc;//选中的文档记录
	private StreamedContent file;


	private Integer docYear = null;// 文档所属年份
	private Integer docMonth = null;// 文档所属月份
	private int currentSelectOrder = -1;
	
	@PostConstruct
	public void init() {
		initTree();
	}

	public void initTree() {
		documentDirs = docManager.findAllDocumentDir();
		root = new DefaultTreeNode();
		LibTreeNode firstNode = new LibTreeNode("rootDir", "文档目录", root);

		List<AppDocumentDir> rootDirs = new ArrayList<>();
		for (AppDocumentDir dir : documentDirs) {
			if (dir.getPid() == null) {
				rootDirs.add(dir);
			}
		}
		sortByOrderNo(rootDirs);
		for (AppDocumentDir d : rootDirs) {
			new LibTreeNode(AppDocumentDir.class.getSimpleName(), d, firstNode);
		}
		firstNode.setExpanded(true);
	}

	/*
	 * 按orderNo升序 排序
	 */
	private void sortByOrderNo(List<AppDocumentDir> dirs) {
		Collections.sort(dirs, new Comparator<AppDocumentDir>() {
			@Override
			public int compare(AppDocumentDir o1, AppDocumentDir o2) {
				return o1.getOrderNo() - o2.getOrderNo();
			}
		});
	}

	/*
	 * 新建目录
	 */
	public void preCreate() {
		createDir = new AppDocumentDir();
		createDir.setCreateDate(new Date());
		createDir.setCreater(getCurrentUser().getCode());
	}

	public void createDir() {
		List<AppDocumentDir> ds = new ArrayList<>();
		if (selected != null) {
			createDir.setPid(selected.getId());
		}
		ds=docManager.findDocumentDirByPid(createDir.getPid());
		for(AppDocumentDir d:ds){
			if (d.getName().equals(createDir.getName())) {
				addErrorMessage(createDir.getName() + "已存在");
				return;
			}
		}
		createDir.setOrderNo(ds.size());
		createDir.setId(ObjectId.get().toString());
		createDir.setType("app");
		docManager.createOrUpdateAppDocumentDir(createDir);
		documentDirs.add(createDir);
		//树
		if(currentSelectedNode.isExpanded()) {
			//如果该节点已经展开，直接new出新建的节点
			new DefaultTreeNode("AppDocumentDir", createDir, currentSelectedNode);
			tempDirs.add(createDir);
		}else {
			currentSelectedNode.setExpanded(true);
			genSubTreeNode(currentSelectedNode);
		}
		addSuccessMessage("新建目录成功");
	}
	
	/*
	 * 编辑目录
	 */
	public void editDir() {
		selected.setCreateDate(new Date());
		selected.setCreater(getCurrentUser().getCode());

		// 判断orderNo有没有变
		if (currentSelectOrder != -1
				&& currentSelectOrder != selected.getOrderNo()) {
			resetOrderNo(selected);
		}else{
			docManager.createOrUpdateAppDocumentDir(selected);
		}
		currentSelectOrder = selected.getOrderNo();
		TreeNode editNode = currentSelectedNode;
		setParentNodeSelected(editNode);
		genSubTreeNode(editNode);
		addSuccessMessage("编辑成功");
	}
	
	
	/**
	 * 设置父节点为选中的节点
	 */
	private void setParentNodeSelected(TreeNode editNode) {
		editNode.getChildren().clear();
		editNode.setSelected(true);
		selected=(AppDocumentDir)editNode.getData();
		list = docManager.findDocumensByPid(selected.getId());
	}
	
	
	/**
	 * 设置父节点为选中的节点
	 */
	private void setParentNodeSelected() {
		currentSelectedNode=currentSelectedNode.getParent();
		currentSelectedNode.getChildren().clear();
		currentSelectedNode.setSelected(true);
		selected=(AppDocumentDir)currentSelectedNode.getData();
		list = docManager.findDocumensByPid(selected.getId());
	}

	/**
	 * 重置顺序
	 * @param selectedDir
	 */
	private void resetOrderNo(AppDocumentDir selectedDir) {
		/*List<AppDocumentDir> dirs = docManager.findDocumentDirByPid(selectedDir
				.getPid());*/
		int newOrderNO=selectedDir.getOrderNo();
		if (!tempDirs.contains(selectedDir)) {
			//删除目录
			for(int i=newOrderNO;i<tempDirs.size();i++){
				tempDirs.get(i).setOrderNo(i);
				docManager.createOrUpdateAppDocumentDir(tempDirs.get(i));
			}
		}else{
			List<AppDocumentDir> ds=ListUtils.sortListByOrderNo(tempDirs,currentSelectOrder,newOrderNO,"orderNo");
			if(ds.size()>0){
				for (AppDocumentDir tmp : ds) {
					docManager.createOrUpdateAppDocumentDir(tmp);
				}
			}else{
				addErrorMessage("编辑失败!");
			}
		}
	}

	// 删除目录
	public void deleteDir() {
		try {
			if (selected == null) {
				addErrorMessage("请选择一个目录");
				return;
			}
			// 删除该目录下所有的目录和文档
			docManager.deleteDirs(selected);
			documentDirs.remove(selected);
			tempDirs.remove(selected);
			resetOrderNo(selected);//已经没有该元素
			currentSelectOrder = selected.getOrderNo();
			setParentNodeSelected();
			genSubTreeNode(currentSelectedNode);
			addSuccessMessage("删除成功");
		} catch (Exception e) {
			e.printStackTrace();
			addErrorMessage("删除失败");
		}
	}

	public void onNodeExpand(NodeExpandEvent event) {
		TreeNode currentNode = event.getTreeNode();
		if ("AppDocumentDir".equals(currentNode.getType())) {
			genSubTreeNode(currentNode);
		}
	}
	private void genSubTreeNode(TreeNode currentNode) {
		if(tempDirs.size()>0) {
			tempDirs.clear();
		}
		AppDocumentDir currentObj = (AppDocumentDir) currentNode.getData();
		for (AppDocumentDir d : documentDirs) {
			if (d.getPid() != null && d.getPid().equals(currentObj.getId())) {
				tempDirs.add(d);
			}
		}
		sortByOrderNo(tempDirs);
		for (AppDocumentDir d : tempDirs) {
			new LibTreeNode("AppDocumentDir", d, currentNode);
		}
	}
	public void onNodeSelect(NodeSelectEvent event) {
		if ("AppDocumentDir".equals(currentSelectedNode.getType())) {
			selected = (AppDocumentDir) currentSelectedNode.getData();
			currentSelectOrder = selected.getOrderNo();
			list = docManager.findDocumensByPid(selected.getId());
		} else {
			selected = null;
		}
	}

	// 上传前清空year和month
	public void preUpload() {
		docYear = null;
		docMonth = null;
	}

	// 文件上传,根据发布周期判断重名文件是否需要替换
	public void handleFileUpload(FileUploadEvent event) {
		UploadedFile file = event.getFile();
		String fileName=file.getFileName();
		List<AppDocument> docs=new ArrayList<AppDocument>();
		if(selected.getDocPublishPeriod()==null){
			docs=docManager.getDocumentByFileName(fileName,selected.getId());
		}else if("年".equals(selected.getDocPublishPeriod())){
			docs=docManager.getDocumentByFileNameAndYear(fileName,selected.getId(),docYear);
		}else if("月".equals(selected.getDocPublishPeriod())){
			docs=docManager.getDocumentByFileNameAndDate(fileName,selected.getId(),docMonth,docYear);
		}
		String houzhuiming = fileName.substring(
				fileName.lastIndexOf("."));
		String id = ObjectId.get().toString();
		String filePathName = id + houzhuiming;
		String uploadpath = pros.getDocumentPath() + filePathName;
		try {
			FileOutputStream fos = new FileOutputStream(uploadpath);
			fos.write(file.getContents());
			fos.close();
			AppDocument ra = new AppDocument();
			ra.setName(fileName);
			ra.setId(id);
			ra.setPid(selected.getId());
			ra.setType("app");
			//系统配置路径的相对路径
			ra.setPath(filePathName);
			ra.setDescription(file.getFileName());
			ra.setCreateDate(new Date());
			ra.setCreater(getCurrentUser().getName());
			ra.setYear(docYear);
			ra.setMonth(docMonth);
			ra.setOrderNo(list.size()+1);
			docManager.createOrUpdateRecordDocument(ra);
			if(docs.size()>0){
				docManager.deleteAPPDocument(docs.get(0));
				list.remove(docs.get(0));
			}
			list.add(ra);
			addSuccessMessage("上传成功");
		} catch (IOException ee) {
			ee.printStackTrace();
			addErrorMessage("上传失败");
		}
	}
	 public void onRowReorder(ReorderEvent event) {
		 //从0开始
		 resetDocListOrderNo();
	}
	// 文件下载
	public void fileDownloadView() {
		try {
			InputStream stream = new FileInputStream(new File(
					pros.getDocumentPath()+selectedDoc.getPath()));
			String fname = CharacterUtil.urlEncode(selectedDoc.getName());
			file = new DefaultStreamedContent(stream,
					"application/octet-stream",fname );

		} catch (UnsupportedEncodingException | FileNotFoundException e) {
			e.printStackTrace();
			addErrorMessage("下载失败");
		}
	}

	// 文件删除
	public void removeSelectDocument() {
		try {
			docManager.deleteAPPDocument(selectedDoc);
			list.remove(selectedDoc);
			resetDocListOrderNo();
			addSuccessMessage("删除成功");
			selectedDoc = null;
		} catch (Exception e) {
			e.printStackTrace();
			addErrorMessage("删除失败");
		}
	}
	
	// 文件转移文件夹
	public void moveSelectDocument() {
		Map<String,Object> options = new HashMap<String, Object>();
        options.put("resizable", false);
        options.put("draggable", false);
        options.put("modal", true);
        options.put("width",350);
        options.put("height",400);
        //openDialog("/ui/document/document_dir_selector.xhtml", options, null);
        PrimeFaces.current().dialog().openDynamic("/ui/document/document_dir_selector.xhtml", options, null);
	}
	public void onDirChosen(SelectEvent event) {
		AppDocumentDir selectedMovedDir=(AppDocumentDir) event.getObject();
		if(!selectedMovedDir.getId().equals(selected.getId())){
			list.remove(selectedDoc);
			resetDocListOrderNo();
		}
		selectedDoc.setPid(selectedMovedDir.getId());
		List<AppDocument> docs=docManager.getDocsByPid(selectedMovedDir.getId());
		selectedDoc.setOrderNo(docs.size()+1);
		docManager.createOrUpdateRecordDocument(selectedDoc);
		selectedDoc = null;
	}
    //刷新docs的文档序号
	private void resetDocListOrderNo(){
		int index=1;
	    for(AppDocument d:list){
	    	d.setOrderNo(index);
	    	index++;
	    	docManager.createOrUpdateRecordDocument(d);
	    }
	}
	//修改文件名
	public void onCellEdit(CellEditEvent event) {
        Object oldValue = event.getOldValue();
        Object newValue = event.getNewValue();
        int rowIndex=event.getRowIndex();
        AppDocument d=list.get(rowIndex);
        if(newValue != null && !newValue.equals(oldValue)) {
        	docManager.createOrUpdateRecordDocument(d);
        }
    }
	
	public void onRowSelect(SelectEvent event){
		selectedDoc = (AppDocument) event.getObject();
	}
	
	public void saveEditDoc() {
		list.remove(selectedDoc);
		list.add(selectedDoc.getOrderNo()-1,selectedDoc);
		resetDocListOrderNo();
		addSuccessMessage("保存成功");
	}
	
	public AppDocumentDir getCreateDir() {
		return createDir;
	}

	public void setCreateDir(AppDocumentDir current) {
		this.createDir = current;
	}

	public AppDocumentDir getSelected() {
		return selected;
	}

	public void setSelected(AppDocumentDir selected) {
		this.selected = selected;
	}

	public StreamedContent getFile() {
		return file;
	}

	public void setFile(StreamedContent file) {
		this.file = file;
	}

	public TreeNode getRoot() {
		return root;
	}

	public void setRoot(TreeNode root) {
		this.root = root;
	}

	public Integer getDocYear() {
		return docYear;
	}

	public void setDocYear(Integer docYear) {
		this.docYear = docYear;
	}

	public Integer getDocMonth() {
		return docMonth;
	}

	public void setDocMonth(Integer docMonth) {
		this.docMonth = docMonth;
	}

	public List<AppDocument> getList() {
		return list;
	}

	public void setList(List<AppDocument> list) {
		this.list = list;
	}

	public TreeNode getCurrentSelectedNode() {
		return currentSelectedNode;
	}

	public void setCurrentSelectedNode(TreeNode currentSelectedNode) {
		this.currentSelectedNode = currentSelectedNode;
	}


	public AppDocument getSelectedDoc() {
		return selectedDoc;
	}

	public void setSelectedDoc(AppDocument selectedDoc) {
		this.selectedDoc = selectedDoc;
	}

}
